package com.opengw.beans;

import javax.net.ssl.SSLHandshakeException;

import org.primefaces.event.FileUploadEvent;
import org.primefaces.model.UploadedFile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.opengw.beans.support.MessagesController;
import com.opengw.beans.support.XMLValidator;
import com.opengw.configuration.CertificateManager;
import com.opengw.configuration.ConfigurationManager;
import com.opengw.configuration.config.BasicAuthentication;
import com.opengw.configuration.entity.CertificateInfo;
import com.opengw.configuration.entity.Content;
import com.opengw.configuration.publish.BasicPublish;
import com.opengw.configuration.publish.XMLPublish;
import com.opengw.configuration.route.Route;
import com.opengw.configuration.services.PublishService;
import com.opengw.configuration.support.Base64;
import com.opengw.configuration.support.Constants;
import com.opengw.configuration.support.SSLCertificateCapturer;
import com.opengw.http.HTTPConnection;
import com.opengw.http.HTTPConstants;

@Component
@Scope("view")
@Qualifier("publishXMLBean")
public class PublishXMLBean {
	
	@Autowired
	private PublishService publishService;
    /** Field description */
    private CertificateInfo certificateInfo;

    /**
    *
    * state = 0 is initialize view and set the request path
    * state = 1 is check the connection to address
    * state = 2 is check the SSL certificate of address
    * state = 3 is set username and password if basic authantication is needed
    * state = 5 is successfully added message
    *
    */
   private int state = 0;
    
    /** Field description */
    @Autowired
    transient private MessagesController messagesController;

    /** Field description */
    private String password;

    /** Field description */
    private String xmlLocation;

    /** Field description */
    private String username;
    
    private String publishName;
    
    private String requestPath;
    private boolean isAuthNeed;
    private boolean fromFile;
    private byte[] xmlContentFile;
    private byte[] xmlContentURL;
    private XMLValidator xmlValidator;
    
    public PublishXMLBean(){
    	
    }
	
	public void checkXML(){
    	boolean hasError = false;
    	
    	if(xmlContentFile != null)
    		fromFile = true;
    	
    	if(xmlLocation == null || xmlLocation.equals("") || (!fromFile && !xmlLocation.startsWith("http://") && !xmlLocation.startsWith("https://"))){
    		hasError = true;
    		messagesController.addError("publishForm:xmlLocation", "dfgd", "ERROR");
    	}
    	
    	if(requestPath == null || requestPath.equals("")){
    		hasError = true;
    		messagesController.addError("publishForm:requestPath", "sdf", "ERROR");
    	}
    	
    	if(publishName == null || publishName.equals("")){
    		hasError = true;
    		messagesController.addError("publishForm:publishName", "ss", "ERROR");
    	}
    	ConfigurationManager configurationManager = ConfigurationManager.getConfigurationManager();
    	Route route = configurationManager.getRoute("/route/" + requestPath);
    	if(route != null){
    		hasError = true;
    		messagesController.addError("publishForm:requestPath", "sss", "UNAVALIABLE NAME");
    	}
    	
    	if(hasError)
    		return;
    	
        if (!fromFile && ((this.state == 0) || (this.state == 1) || (this.state == 3))) {
        	try{
	        	HTTPConnection conn = new HTTPConnection(xmlLocation);
	        	conn.setDoInput(true);
	        	conn.connect();
	        	if(conn.getHTTPCode() == 200){
	        		xmlContentURL = conn.getContent();
	        		xmlValidator = new XMLValidator(xmlContentURL);
	        		this.state = 4;
	        	} else if(conn.getHTTPCode() == 401)
	        		this.state = 3;
	        	else{
	        		this.state = 0;
	        		messagesController.addError("HTTP" + conn.getHTTPCode() + " can not access address", "");
        		}
        	} catch (SSLHandshakeException e) {
        		getCertificateFromURL();
        	} catch (Exception e) {
        		e.printStackTrace();
        		messagesController.addError(e.getMessage(), "");
			}
        } else if(fromFile){
        	try{
        		xmlValidator = new XMLValidator(xmlContentFile);
	        	state = 4;
        	} catch (Exception e) {
        		e.printStackTrace();
        		messagesController.addError(e.getMessage(), "");
			}
        }
	}
	
    public void setConfiguration(){
    	addXMLPublish();
    	this.state = 5;
    	messagesController.addInfo("SUCCESFULLY ADDED", "SUCCESFULLY ADDED DETAIL");
    }
	
    public void basicAuthCheckURL(){
    	if(this.state == 3){
    		try{
    			HTTPConnection conn = new HTTPConnection(xmlLocation);
    			String authHeader = "Basic ";
    			Base64 base64 = new Base64();
    			String encodedToken = base64.encode((this.username + ":" + this.password).getBytes());
    			authHeader += encodedToken;
    			conn.setRequestHeader(HTTPConstants.AUTHORIZATION_HEADER, authHeader);
    			conn.setDoInput(true);
    			conn.connect();
	        	if(conn.getHTTPCode() == 200){
	        		xmlContentURL = conn.getContent();
	        		xmlValidator = new XMLValidator(xmlContentURL);
	        		this.state = 4;
	        		isAuthNeed = true;
	        	} else if(conn.getHTTPCode() == 401)
	        		this.state = 3;
	        	else{
	        		this.state = 0;
	        		messagesController.addError("HTTP" + conn.getHTTPCode() + " can not access address", "");
        		}
    		} catch (Exception e) {
    			messagesController.addError(e.getMessage(), "");
			}
    	}
    }
    
    private void addXMLPublish(){
    	XMLPublish publish = new XMLPublish();
    	publish.setPublishName(publishName);
    	publish.setOriginalURL(xmlLocation);
    	publish.setFromFile(fromFile);
    	Content content = null;
    	if(fromFile)
    		content = new Content(HTTPConstants.TEXT_XML_CONTENT_TYPE, xmlContentFile);
    	else
    		content = new Content(HTTPConstants.TEXT_XML_CONTENT_TYPE, xmlContentURL);
    	publish.setContent(content);
    	ConfigurationManager configurationManager = ConfigurationManager.getConfigurationManager();
    	Route route = new Route();
    	route.setConnectTimeOut(configurationManager.getDefaultConnectTimeOut());
    	route.setReadTimeOut(configurationManager.getDefaultReadTimeOut());
    	route.setRequestPath(Constants.ROUTE_PUBLISH_PATH + requestPath);
    	route.setRouteURL(xmlLocation);	
		route.setDefaultContent(content);
    	
    	route.setAvailableMethods(HTTPConstants.HTTP_METHOD_GET);
    	
    	if(isAuthNeed){
    		BasicAuthentication authenticationConfig = new BasicAuthentication(false);
    		authenticationConfig.setUsername(username);
    		authenticationConfig.setPassword(password);
    		route.addRouteConfig(authenticationConfig);
    	}
    	
    	publish.setRoute(route);
    	publishService.savePublish(publish);
    	
    	configurationManager.addPublish(publish);
    	
    	
    }
	
    private void getCertificateFromURL(){
    	if (xmlLocation.startsWith(HTTPConstants.HTTPS_PROTOCOL) && (this.state == 0)) {
            try {
                SSLCertificateCapturer certificateCapturer = new SSLCertificateCapturer(xmlLocation);
                this.certificateInfo = new CertificateInfo(certificateCapturer.captureSSLCertificate());
                this.state       = 2;
            } catch (Exception e) {
            	messagesController.addError(e.getMessage(), "");
            }
        }
    }
    
    public void addCertificaToTrustStore(){
    	CertificateManager manager = CertificateManager.getCertificateManager();
    	try{
    		manager.addCertificate(this.certificateInfo.getCertificate());
    	} catch (Exception e) {
    		messagesController.addError(e.getMessage(), "");
		}
    	this.state = 1;
    	checkXML();
    }
	
	public void handleFileUpload(FileUploadEvent event){
		UploadedFile file = event.getFile();
		xmlContentFile = file.getContents();
		xmlLocation = file.getFileName();
		
	}

	public void setFromFile(boolean fromFile) {
		this.fromFile = fromFile;
	}

	public boolean isFromFile() {
		return fromFile;
	}

	public void setRequestPath(String requestPath) {
		this.requestPath = requestPath;
	}

	public String getRequestPath() {
		return requestPath;
	}

	public void setPublishName(String publishName) {
		this.publishName = publishName;
	}

	public String getPublishName() {
		return publishName;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getUsername() {
		return username;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getPassword() {
		return password;
	}

	public void setCertificateInfo(CertificateInfo certificateInfo) {
		this.certificateInfo = certificateInfo;
	}

	public CertificateInfo getCertificateInfo() {
		return certificateInfo;
	}

	public void setXmlLocation(String xmlLocation) {
		this.xmlLocation = xmlLocation;
	}

	public String getXmlLocation() {
		return xmlLocation;
	}

	public void setState(int state) {
		this.state = state;
	}

	public int getState() {
		return state;
	}

	public String getContentString() {
		try{
			return xmlValidator.getDocumentString();
		} catch (Exception e) {
		}
		
		return "-";
	}

}
